home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 2 / Apprentice-Release2.iso / Source Code / C++ / Libraries / KPlib 1.2.1 / sample_progs / deps.cxx < prev    next >
Encoding:
C/C++ Source or Header  |  1994-11-07  |  6.3 KB  |  185 lines  |  [TEXT/R*ch]

  1. /*
  2.     This program accepts a list of C or C++ source files for a project
  3.     and outputs a dependency list suitable for a Makefile.  It
  4.     recursively parses the include files to insure that all
  5.     dependencies are noted.  Relative and absolute pathnames for both
  6.     source and include files are correctly handled.  Only include lines
  7.     that start with `#include "' are looked at.  Commented-out include
  8.     lines are not ignored.
  9.  
  10.     Only dependency lists for the object files corresponding to the
  11.     source files are generated.  It is the responsibility of the
  12.     programmer to supply the dependency lists for the desired
  13.     executables and to define $(CC) and $(CFLAGS).  If a file called
  14.     `.makeheader' exists in the project directory, the contents of this
  15.     file will be prepended to the output of this program.  Thus, if the
  16.     user places user-defined dependencies in this file, the command
  17.  
  18.             deps *.c > Makefile
  19.  
  20.     will correctly create a complete Makefile for a C project.
  21.  
  22.     Written by Keith Pomakis on October 10, 1994.  Public Domain.
  23. */
  24.  
  25. #include <iostream.h>
  26. #include <fstream.h>
  27. #include <string.h>
  28. #include <time.h>
  29. #include "../KPbasic.h"
  30. #include "../KPList.h"
  31. #include "../KPString.h"
  32. #include "../KPSet.h"
  33.  
  34. /****************************************************************************/
  35.  
  36. KPString progname;
  37.  
  38. const char *const headerfile = ".makeheader";
  39.  
  40. template class KPList<KPString>;  // Explicit instantiation.
  41.  
  42. /****************************************************************************/
  43.  
  44. static inline KPString base(const KPString &string)
  45. { return string.tokens('/').tail(); }
  46.  
  47. static inline KPString path(const KPString &string)
  48. { return string.substr(0, string.length() - base(string).length()); }
  49.  
  50. static inline bool is_relative(const KPString &string)
  51. { return string.is_empty() || string[0] != '/'; }
  52.  
  53. static inline KPString root(const KPString &string)
  54. { return string.tokens('.').head(); }
  55.  
  56. static void process_header();
  57. static void process_source(const KPString &sourcename);
  58. static bool process_file(const KPString &filename, KPSet<KPString> &includes,
  59.                          KPString pathname);
  60.  
  61. /****************************************************************************/
  62.  
  63. int
  64. main(int argc, char *argv[])
  65. {
  66.     progname = base(argv[0]);
  67.  
  68.     if (argc < 2) {
  69.         cerr << "Usage: " << progname << " -help\n"
  70.              << "       " << progname << " <sourcefile> ...\n";
  71.         exit(EXIT_FAILURE);
  72.     }
  73.  
  74.     if (strncmp(argv[1], "-h", 2) == 0) {
  75.         cout <<
  76.         "This program accepts a list of C or C++ source files for a project\n"
  77.         "and outputs a dependency list suitable for a Makefile.  It\n"
  78.         "recursively parses the include files to insure that all\n"
  79.         "dependencies are noted.  Relative and absolute pathnames for both\n"
  80.         "source and include files are correctly handled.  Only include lines\n"
  81.         "that start with `#include \042' are looked at.  Commented-out\n"
  82.         "include lines are not ignored.\n\n"
  83.         "Only dependency lists for the object files corresponding to the\n"
  84.         "source files are generated.  It is the responsibility of the\n"
  85.         "programmer to supply the dependency lists for the desired\n"
  86.         "executables and to define $(CC) and $(CFLAGS).  If a file called\n"
  87.         "`.makeheader' exists in the project directory, the contents of this\n"
  88.         "file will be prepended to the output of this program.  Thus, if the\n"
  89.         "user places user-defined dependencies in this file, the command\n\n"
  90.         "        " << progname << " *.c > Makefile\n\n"
  91.         "will correctly create a complete Makefile for a C project.\n\n"
  92.         "Written by Keith Pomakis on October 10, 1994.  Public Domain.\n";
  93.         exit(EXIT_SUCCESS);
  94.     }
  95.  
  96.     process_header();
  97.  
  98.     time_t current_time = time(NULL);
  99.     cout << "\n###########################################################\n";
  100.     cout << "#\n";
  101.     cout << "#  File dependencies generated by \042" << progname << "\042.\n";
  102.     cout << "#  " << ctime(¤t_time);
  103.     cout << "#\n";
  104.     cout << "###########################################################\n\n";
  105.  
  106.     for (int i=1; i<argc; i++)
  107.         process_source(argv[i]);
  108.  
  109.     return 0;
  110. }
  111.  
  112. /****************************************************************************/
  113.  
  114. static void
  115. process_header()
  116. {
  117.     ifstream stream(headerfile, ios::in);
  118.     if (!stream) return;
  119.  
  120.     KPString line;
  121.  
  122.     while (!stream.eof()) {
  123.         line.read_line(stream);
  124.         if (!stream.eof()) cout << line << '\n';
  125.     }
  126. }
  127.  
  128. /****************************************************************************/
  129.  
  130. static void
  131. process_source(const KPString &sourcename)
  132. {
  133.     KPSet<KPString> includes = sourcename;
  134.  
  135.     cout << root(base(sourcename)) << ".o: \\\n";
  136.  
  137.     if (process_file(sourcename, includes, path(sourcename))) {
  138.         KPReadOnlyIterator<KPString> iter(includes.list());
  139.         FOREACH(iter) {
  140.             cout << "    " << *iter;
  141.             if (!iter.at_end()) cout << " \\";
  142.             cout << '\n';
  143.         }
  144.         cout << "\t$(CC) $(CFLAGS) -c " << sourcename << "\n\n";
  145.     }
  146. }
  147.  
  148. /****************************************************************************/
  149.  
  150. static bool
  151. process_file(const KPString &filename, KPSet<KPString> &includes, KPString pathname)
  152. {
  153.     ifstream stream(filename, ios::in);
  154.     if (!stream) {
  155.         cerr << progname << ": error opening file \042" << filename << "\042\n";
  156.         return false;
  157.     }
  158.  
  159.     KPString line;
  160.  
  161.     while (!stream.eof()) {
  162.         line.read_line(stream);
  163.         if (line.length() > 11 && memcmp(line, "#include \042", 10) == 0) {
  164.             const int second_quote = line.index_of('\042', 10);
  165.             if (second_quote < 0 || second_quote == 10) {
  166.                 cerr << progname << ": error in file \042" << filename
  167.                      << "\042 - bad include line:\n" << line << '\n';
  168.                 return false;
  169.             }
  170.             KPString new_include = line.substr(10, second_quote-10);
  171.             if (is_relative(new_include)) new_include = pathname + new_include;
  172.             if (!includes.contains(new_include)) {
  173.                 includes += new_include;
  174.                 if (!process_file(new_include, includes, path(new_include)))
  175.                     return false;
  176.             }
  177.         }
  178.     }
  179.  
  180.     return true;
  181. }
  182.  
  183. /****************************************************************************/
  184.  
  185.